#ifndef _HELIX_MATH_TESTS_H_
#define _HELIX_MATH_TESTS_H_

// VectorTests.h
#include <cxxtest/TestSuite.h>
#include "../Helix/Log.h"
#include "../Helix/HObject.h"
#include "../Helix/Util/PointerCheck.h"
#include "../Helix/Math/Vector.h"
#include "../Helix/Math/Matrix4x4.h"

using namespace helix;

static float p1[3]={1.0f,0.0f,0.0f};
static float p2[3]={1.0f,1.0f,1.0f};
static float p3[3]={-34.5f,29.4f,-2.058f};
static float p4[3]={6.5f,-65.46f,235.74f};


class VectorTest : public CxxTest::TestSuite
{
public:
	Vector *v1;
	Vector *v2;
	Vector *v3;
	Vector *v4;

	void setUp()
	{
		printf("\n\nVectorTest::");

		v1=new Vector(p1[0],p1[1],p1[2]);
		v2=new Vector(p2[0],p2[1],p2[2]);
		v3=new Vector(p3[0],p3[1],p3[2]);
		v4=new Vector(p4[0],p4[1],p4[2]);
	}

	void tearDown()
	{
		PtrCheck::safeDelete(v1,"Vector 1");
		PtrCheck::safeDelete(v2,"Vector 2");
		PtrCheck::safeDelete(v3,"Vector 3");
		PtrCheck::safeDelete(v4,"Vector 4");
	}

	void testAddVectors( void )
	{
		printf("testAddVectors\n");
		Vector test=*v1+*v2;
		TS_ASSERT_DELTA(p1[0]+p2[0],test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]+p2[1],test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]+p2[2],test.z(),0.000000001);
	}

	void testSubtractVectors( void )
	{
		printf("testSubtractVectors\n");
		Vector test=*v1-*v2;
		TS_ASSERT_DELTA(p1[0]-p2[0],test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]-p2[1],test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]-p2[2],test.z(),0.000000001);
	}

	void testAddAssignVectors( void )
	{
		printf("testAddAssignVectors\n");
		Vector test=*v1;
		test+=*v2;
		TS_ASSERT_DELTA(p1[0]+p2[0],test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]+p2[1],test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]+p2[2],test.z(),0.000000001);
	}

	void testMultiplyVectorByScalar( void)
	{
		printf("testMultiplyVectorByScalor\n");
		float scalar=34.05f;
		Vector test=*v1 * scalar;
		TS_ASSERT_DELTA(p1[0]*scalar,test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]*scalar,test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]*scalar,test.z(),0.000000001);
	}

	void testMultiplyVectorsByComponent( void)
	{
		printf("testMultiplyVectorsByComponent\n");
		Vector test=*v1 * *v2;
		TS_ASSERT_DELTA(p1[0]*p2[0],test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]*p2[1],test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]*p2[2],test.z(),0.000000001);
	}

	void testDivideVectorByScalar( void)
	{
		printf("testDivideVectorByScalor\n");
		float scalar=34.05;
		Vector test=*v1 / scalar;
		TS_ASSERT_DELTA(p1[0]/scalar,test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]/scalar,test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]/scalar,test.z(),0.000000001);
	}

	void testDivideVectorsByComponent( void)
	{
		printf("testDivideVectorsByComponent\n");
		Vector test=*v1 / *v2;
		TS_ASSERT_DELTA(p1[0]/p2[0],test.x(),0.000000001);
		TS_ASSERT_DELTA(p1[1]/p2[1],test.y(),0.000000001);
		TS_ASSERT_DELTA(p1[2]/p2[2],test.z(),0.000000001);
	}

	void testDotProduct( void)
	{
		printf("testDotProduct\n");
		float test=(*v1).dot(*v2);
		TS_ASSERT_DELTA(p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2],test,0.000000001);
	}

	void testCrossProduct( void)
	{
		printf("testCrossProduct\n");
		Vector test=(*v2).cross(*v3);
		float realx=p2[1]*p3[2]-p3[1]*p2[2];
		float realy=-(p2[0]*p3[2]-p3[0]*p2[2]);
		float realz=p2[0]*p3[1]-p3[0]*p2[1];
		TS_ASSERT_DELTA(realx,test.x(),0.000000001);
		TS_ASSERT_DELTA(realy,test.y(),0.000000001);
		TS_ASSERT_DELTA(realz,test.z(),0.000000001);
	}

	void testNormalizeVector( void)
	{
		printf("testNormalizeVector\n");
		Vector test=(*v3).normalize();
		float length=(float)sqrt((double)(p3[0]*p3[0]+p3[1]*p3[1]+p3[2]*p3[2]));
		TS_ASSERT_DELTA(p3[0]/length,test.x(),0.00001);
		TS_ASSERT_DELTA(p3[1]/length,test.y(),0.00001);
		TS_ASSERT_DELTA(p3[2]/length,test.z(),0.00001);
	}

	void testCalculateLength( void)
	{
		printf("testCalculateLength\n");
		float test=(*v3).length();
		float length=(float)sqrt((double)(p3[0]*p3[0]+p3[1]*p3[1]+p3[2]*p3[2]));
		TS_ASSERT_DELTA(length,test,0.00001);
	}

	void testVectorEquals( void)
	{
		printf("testVectorEquals\n");
		Vector v1(1.0,1.0,1.0);
		Vector v2(1.0,1.0,1.0);
		TS_ASSERT_EQUALS(true,v1==v2);

		v2 = Vector(1.0,3.0,1.0);
		TS_ASSERT_EQUALS(false,v1==v2);
	}

	void testVectorNotEquals( void)
	{
		printf("testVectorNotEquals\n");
		Vector v1(1.0,1.0,1.0);
		Vector v2(1.0,4.0,1.0);
		TS_ASSERT_EQUALS(true,v1!=v2);

		v2 = Vector(1.0,1.0,1.0);
		TS_ASSERT_EQUALS(false,v1!=v2);
	}

	void testTranslationMatrix( void)
	{
		printf("testTranslationMatrix\n");
		Matrix4x4 m(2.0,1.0,3.0);
		Vector v1(1.0,4.0,1.0);

		Vector v2 = m*v1;

		TS_ASSERT_DELTA(3.0,v2.x(),0.0001);
		TS_ASSERT_DELTA(5.0,v2.y(),0.0001);
		TS_ASSERT_DELTA(4.0,v2.z(),0.0001);
	}
};

#endif
